package com.ymatou.iapi.optrade.testcase;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;

import org.apache.http.client.ClientProtocolException;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;

import com.ymatou.iapi.optrade.parameter.enums.PayStatusEnum;
import com.ymatou.iapi.optrade.parameter.enums.PayTypeEnum;
import com.ymatou.iapi.optrade.parameter.req.ChannelPayReq;
import com.ymatou.iapi.optrade.parameter.utill.Utils;
import com.ymatou.iapi.optrade.resp.Order;
import com.ymatou.iapi.optrade.resp.TradingServiceResp;
import com.ymatou.iapi.optrade.service.ChannelPayCall;
import com.ymt.core.tool.Logger;
import com.ymt.utils.annotation.TestCase;
import com.ymt.utils.tag.P3;
import com.ymttest.business.service.YMTTrading.TradingPlaceAnliOrderCallService;
import com.ymttest.business.service.YMTTrading.TradingPlaceOrderCallService;
import com.ymttest.database.sharding.db.sharding.model.OrderPo;
import com.ymttest.database.sharding.db.sharding.model.OrderStatusLogPo;
import com.ymttest.database.sharding.db.sharding.model.PaymentPo;
import com.ymttest.database.sharding.db.sqlwapper.OrderShardingWapper;
import com.ymttest.utils.DataUtil;

public class Ts_ChannelPay {

	private static ChannelPayReq channelPayReq;
	private static ChannelPayCall channelPayCall;
	
	private static OrderShardingWapper orderShardingWapper = new OrderShardingWapper();
	
	@BeforeClass
	public static void setUp() {
		Logger.createResultFile("买手确认收款");
	}

	@Before
	public void caseUp() {
		channelPayReq = new ChannelPayReq();
		channelPayCall = new ChannelPayCall();
	}

	@AfterClass
	public static void tearDown() {
		Logger.generateResult(channelPayCall.getOpurl());
	}

	@After
	public void caseDown() {
		Logger.end();
	}
	
	/**
	 * 支付完成后（包括第三方支付回调交易完成）,校验订单数据
	 * 
	 * @param paymentId
	 * @param useAccountAmount
	 * @param orderList
	 * @param cmbDiscountAmount
	 * @param placeEngageReq
	 * @throws InterruptedException 
	 * @throws IOException 
	 * @throws ClientProtocolException 
	 */
	private void verifyDb(long userId, long tradingId, BigDecimal useAccountAmount,
			List<Order> orderList) throws InterruptedException, ClientProtocolException, IOException {

		BigDecimal payDeductAmount = BigDecimal.ZERO;

		BigDecimal orderDiscount = BigDecimal.ZERO;
		BigDecimal realNeedPayAmount = BigDecimal.ZERO;
		BigDecimal freight = BigDecimal.ZERO;
		BigDecimal totalYmtCouponAmount = BigDecimal.ZERO;
		BigDecimal totalSellerCouponAmount = BigDecimal.ZERO;
		BigDecimal totalCardAmount = BigDecimal.ZERO;
		BigDecimal needPayAmount = BigDecimal.ZERO;
		BigDecimal totalTaxFee = BigDecimal.ZERO;
		BigDecimal totalRebateAmount = BigDecimal.ZERO;
		
		String payment_payCurrency = null;
		
		long paymentId = 0L;
		
		BigDecimal[] realNeedPayAmountList = new BigDecimal[orderList.size()];
		
		totalYmtCouponAmount = orderList.stream()
				.map(o -> o.getOrderPo().getYmtCouponAmount())
				.reduce(BigDecimal.ZERO, BigDecimal::add);
		totalSellerCouponAmount = orderList.stream()
				.map(o -> o.getOrderPo().getSellerCouponAmount())
				.reduce(BigDecimal.ZERO, BigDecimal::add);
		totalCardAmount = orderList.stream()
				.map(o -> o.getOrderPo().getCardAmount())
				.reduce(BigDecimal.ZERO, BigDecimal::add);
		totalTaxFee = orderList.stream()
				.map(o -> o.getOrderPo().getTaxFee())
				.reduce(BigDecimal.ZERO, BigDecimal::add);
		totalRebateAmount = orderList.stream()
				.map(o -> o.getOrderPo().getRebatePaidAmount())
				.reduce(BigDecimal.ZERO, BigDecimal::add);

		for (int i = 0; i < orderList.size(); i++) {

			orderShardingWapper.clearCache();
			
			OrderPo orderPo = orderShardingWapper.selectOrderbyOrderId(
					orderList.get(i).getOrderId());
			orderDiscount = orderDiscount.add(orderPo.getOrderDiscount());

			freight = freight.add(orderPo.getFreight());
			realNeedPayAmountList[i] = orderPo.getPayableAmount();
			realNeedPayAmount = realNeedPayAmount.add(orderPo
					.getPayableAmount());
			
			paymentId = orderPo.getPaymentId();
		}

		// 该交易需要支付的总金额
		needPayAmount = orderList.stream()
				.map(o -> o.getOrderPo().getTotalPrice())
				.reduce(BigDecimal.ZERO, BigDecimal::add)
				.subtract(payDeductAmount).add(orderDiscount).add(freight).add(totalTaxFee)
				.subtract(totalSellerCouponAmount)
				.subtract(totalYmtCouponAmount)
				.subtract(totalCardAmount)
				.subtract(totalRebateAmount);
		
		// 用户支付的余额
		useAccountAmount = Utils.zeroIfNull(useAccountAmount);

		// 支付表(payment)
		PaymentPo paymentPo = orderShardingWapper.selectPaymentById(paymentId);

		PaymentPo expectedPayment = new PaymentPo();

		expectedPayment.setUserId(userId);
		expectedPayment.setPaymentId(paymentId);
		expectedPayment.setAccountAmount(BigDecimal.ZERO);
		expectedPayment.setPayableAmount(needPayAmount);
		expectedPayment.setThirdpartyAmount(useAccountAmount);

		expectedPayment.setTradeType(1);
		expectedPayment.setPayStatus(PayStatusEnum.MINUS_BALANCE_SUCCESS
				.getCode());
		expectedPayment.setPayType(PayTypeEnum.OFFLINE_PAY.getCode());

		expectedPayment.setThirdpartyDiscount(BigDecimal.ZERO);
		expectedPayment.setPayDeductAmount(payDeductAmount);

		expectedPayment.setRealPaidAmount(realNeedPayAmount);
		expectedPayment.setRetryTimes(0);
		
		expectedPayment.setPayCurrency(payment_payCurrency);

		expectedPayment.setAppName(null);

		expectedPayment.setSettleCurrency(null);
		expectedPayment.setSettleRate(null);
		expectedPayment.setGatewayPayType(null);

		verifyPaymentDb(expectedPayment, paymentPo);

		BigDecimal[] weights = new BigDecimal[orderList.size()];

		for (int i = 0; i < orderList.size(); i++) {
			weights[i] = realNeedPayAmountList[i];
		}

		for (int i = 0; i < orderList.size(); i++) {

			// 订单号
			long orderId = orderList.get(i).getOrderId();

			// 订单表(order)
			OrderPo ymtOrders = orderShardingWapper.selectOrderbyOrderId(orderId);

			Logger.comment("验证订单号:" + orderId);

			Logger.comment("验证订单表(order)表");

			Logger.verifyEquals(2, ymtOrders.getOrderStatus(), "验证数据库OrderStatus");
			List<OrderStatusLogPo> results = orderShardingWapper.selectOrderStatusesLogByOrderId(orderId);
			
			Logger.verifyEquals(1, results.size(), "验证数据库OrderStatusLog数量");
			
			for(OrderStatusLogPo result : results) {
				
				Logger.verifyEquals("渠道订单支付完成", result.getMemo(), "验证数据库memo");
			}
			
			Logger.verifyEquals(paymentId, ymtOrders.getPaymentId(),
					"验证数据库PaymentId");
			DataUtil.verifyDecimalEquals(BigDecimal.ZERO, BigDecimal.ZERO,
					"验证数据库ThirdpartyPaidAmount");
			DataUtil.verifyDecimalEquals(BigDecimal.ZERO, BigDecimal.ZERO,
					"验证数据库AccountPaidAmount");
		}
	}

	/**
	 * 支付表(payment)
	 * 
	 * @param expectedPayment
	 * @param actualPayment
	 */
	private void verifyPaymentDb(PaymentPo expectedPayment,
			PaymentPo actualPayment) {

		Logger.comment(String.format("验证支付表(payment) ,paymentId :%s",
				expectedPayment.getPaymentId()));

		DataUtil.verifyDecimalEquals(expectedPayment.getThirdpartyAmount(),
				actualPayment.getThirdpartyAmount(), "验证数据库ThirdpartyAmount");
		DataUtil.verifyDecimalEquals(expectedPayment.getRealPaidAmount(),
				actualPayment.getRealPaidAmount(), "验证数据库RealPaidAmount");
		
		Logger.verifyEquals(expectedPayment.getTradeType(),
				actualPayment.getTradeType(), "验证数据库TradeType");
		Logger.verifyEquals(true,
				Utils.calcTimeSpanMin(actualPayment.getUpdateTime()) < 2,
				"验证数据库UpdateTime跟系统当前时间差为2分钟内");
		Logger.verifyEquals(true,
				Utils.calcTimeSpanMin(actualPayment.getAddTime()) < 2,
				"验证数据库AddTime跟系统当前时间差为2分钟内");

		DataUtil.verifyDecimalEquals(expectedPayment.getPayableAmount(),
				actualPayment.getPayableAmount(), "验证数据库PayableAmount");
		Logger.verifyEquals(expectedPayment.getPaymentId(),
				actualPayment.getPaymentId(), "验证数据库PaymentId");
		Logger.verifyEquals(expectedPayment.getUserId(),
				actualPayment.getUserId(), "验证数据库UserId");
		DataUtil.verifyDecimalEquals(expectedPayment.getThirdpartyDiscount(),
				actualPayment.getThirdpartyDiscount(),
				"验证数据库ThirdpartyDiscount");

		DataUtil.verifyDecimalEquals(expectedPayment.getPayDeductAmount(),
				actualPayment.getPayDeductAmount(), "验证数据库payDeductAmount");

		Logger.verifyEquals(expectedPayment.getPayStatus(),
				actualPayment.getPayStatus(), "验证数据库PayStatus");

		Logger.verifyEquals(expectedPayment.getRetryTimes(),
				actualPayment.getRetryTimes(), "验证数据库RetryTimes");

		DataUtil.verifyDecimalEquals(expectedPayment.getAccountAmount(),
				actualPayment.getAccountAmount(), "验证数据库AccountAmount");
		Logger.verifyEquals(expectedPayment.getPayType(),
				actualPayment.getPayType(), "验证数据库PayType");

		Logger.verifyEquals(expectedPayment.getMemo(), actualPayment.getMemo(),
				"验证数据库Memo");

		Logger.verifyEquals(expectedPayment.getSettleCurrency(),
				actualPayment.getSettleCurrency(), "验证数据库SettleCurrency");
		Logger.verifyEquals(expectedPayment.getSettleRate(),
				actualPayment.getSettleRate(), "验证数据库SettleRate");
		Logger.verifyEquals(expectedPayment.getForeignAmount(),
				actualPayment.getForeignAmount(), "验证数据库ForeignAmount");
		Logger.verifyEquals(expectedPayment.getRealForeignAmount(),
				actualPayment.getRealForeignAmount(), "验证数据库RealForeignAmount");
		Logger.verifyEquals(expectedPayment.getPayCurrency(),
				actualPayment.getPayCurrency(), "验证数据库PayCurrency");
		Logger.verifyEquals(expectedPayment.getExchangeRate(),
				actualPayment.getExchangeRate(), "验证数据库ExchangeRate");
		Logger.verifyEquals(expectedPayment.getShenqiPaymentRmbAmount(),
				actualPayment.getShenqiPaymentRmbAmount(), "验证数据库ShenqiPaymentRmbAmount");
		Logger.verifyEquals(expectedPayment.getAppName(),
				actualPayment.getAppName(), "验证数据库appName");
		Logger.verifyEquals(expectedPayment.getGatewayPayType(),
				actualPayment.getGatewayPayType(), "验证数据库gatewayPayType");
	}
	
	@Test
	@Category(P3.class)
	@TestCase
	public void Tc_ChannelPay_001() {
		Logger.start(true, "创建一个ordertype不为4的订单，使用渠道支付失败");
		try {
			
			Logger.comment("前置数据准备");
			
			TradingServiceResp placeOrderResp = TradingPlaceOrderCallService.placeOrderWithLuxury(false);
			
			long userId = placeOrderResp.getUserId();
			long orderId = placeOrderResp.getOrderList().get(0).getOrderId();
			
			Logger.comment("前置数据准备结束");
			
			channelPayReq.setOrderId(orderId);
			channelPayReq.setChannel(1);
			channelPayReq.setUserId(userId);
			
			channelPayCall.setData(channelPayReq);
			channelPayCall.callService();

			Logger.verifyEquals("与实际订单渠道不匹配", channelPayCall.getMsg(), "验证errorMessage");
			Logger.verifyEquals("ERR_CONDITION_NOTMATCH", channelPayCall.getCode(), "验证errorCode");

		} catch (Exception e) {
			Logger.fail(e);
		}
	}
	
	@Test
	@Category(P3.class)
	@TestCase
	public void Tc_ChannelPay_002() {
		Logger.start(true, "创建一个ordertype为4的订单，使用渠道支付成功");
		try {
			
			Logger.comment("前置数据准备");
			
			TradingServiceResp placeOrderResp = TradingPlaceAnliOrderCallService
					.placeAnlihuiOrder(BigDecimal.ZERO, false, 4);
			long userId = placeOrderResp.getUserId();
			long orderId = placeOrderResp.getOrderList().get(0).getOrderId();
			
			Logger.comment("前置数据准备结束");
			
			channelPayReq.setOrderId(orderId);
			channelPayReq.setChannel(1);
			channelPayReq.setUserId(userId);
			
			channelPayCall.setData(channelPayReq);
			channelPayCall.callService();

			verifyDb(userId, placeOrderResp.getTradingId(), placeOrderResp.getPayableAmount(),
					placeOrderResp.getOrderList());

		} catch (Exception e) {
			Logger.fail(e);
		}
	}
	
	@Test
	@Category(P3.class)
	@TestCase
	public void Tc_ChannelPay_003() {
		Logger.start(true, "创建一个ordertype为4的订单，使用渠道支付成功，再次支付");
		try {
			
			Logger.comment("前置数据准备");
			
			TradingServiceResp placeOrderResp = TradingPlaceAnliOrderCallService
					.placeAnlihuiOrder(BigDecimal.ZERO, false, 4);
			long userId = placeOrderResp.getUserId();
			long orderId = placeOrderResp.getOrderList().get(0).getOrderId();
			
			Logger.comment("前置数据准备结束");
			
			// 第一次支付成功
			channelPayReq.setOrderId(orderId);
			channelPayReq.setChannel(1);
			channelPayReq.setUserId(userId);
			
			channelPayCall.setData(channelPayReq);
			channelPayCall.callService();
			
			// 第二次支付
			channelPayCall.callService();

			Logger.verifyEquals("订单状态不匹配", channelPayCall.getMsg(), "验证errorMessage");
			Logger.verifyEquals("ERR_STATUS_NOTMATCH", channelPayCall.getCode(), "验证errorCode");

		} catch (Exception e) {
			Logger.fail(e);
		}
	}
	
	@Test
	@Category(P3.class)
	@TestCase
	public void Tc_ChannelPay_004() {
		Logger.start(true, "使用渠道支付成功，orderid为空，支付失败");
		try {
			
			channelPayReq.setOrderId(0L);
			channelPayReq.setChannel(1);
			channelPayReq.setUserId(1234L);
			
			channelPayCall.setData(channelPayReq);
			channelPayCall.callService();
			
			Logger.verifyEquals("orderId:订单号不能为空", channelPayCall.getMsg(), "验证errorMessage");
			Logger.verifyEquals("ILLEGAL_ARGUMENT", channelPayCall.getCode(), "验证errorCode");

		} catch (Exception e) {
			Logger.fail(e);
		}
	}
	
	@Test
	@Category(P3.class)
	@TestCase
	public void Tc_ChannelPay_005() {
		Logger.start(true, "使用渠道支付成功，channel为空，支付失败");
		try {
			
			channelPayReq.setOrderId(1234L);
			channelPayReq.setChannel(0);
			channelPayReq.setUserId(1234L);
			
			channelPayCall.setData(channelPayReq);
			channelPayCall.callService();

			Logger.verifyEquals("channel:渠道订单的渠道未提供", channelPayCall.getMsg(), "验证errorMessage");
			Logger.verifyEquals("ILLEGAL_ARGUMENT", channelPayCall.getCode(), "验证errorCode");

		} catch (Exception e) {
			Logger.fail(e);
		}
	}
	
	@Test
	@Category(P3.class)
	@TestCase
	public void Tc_ChannelPay_006() {
		Logger.start(true, "使用渠道支付成功，userId为空，支付失败");
		try {
			
			channelPayReq.setOrderId(1234L);
			channelPayReq.setChannel(1);
			channelPayReq.setUserId(0L);
			
			channelPayCall.setData(channelPayReq);
			channelPayCall.callService();

			Logger.verifyEquals("userId:userId未提供", channelPayCall.getMsg(), "验证errorMessage");
			Logger.verifyEquals("ILLEGAL_ARGUMENT", channelPayCall.getCode(), "验证errorCode");

		} catch (Exception e) {
			Logger.fail(e);
		}
	}
	
	@Test
	@Category(P3.class)
	@TestCase
	public void Tc_ChannelPay_007() {
		Logger.start(true, "使用渠道支付成功，不存在的orderId，支付失败");
		try {
			
			channelPayReq.setOrderId(112312312312321334L);
			channelPayReq.setChannel(1);
			channelPayReq.setUserId(1L);
			
			channelPayCall.setData(channelPayReq);
			channelPayCall.callService();

			Logger.verifyEquals(
					String.format("订单号%s不存在", channelPayReq.getOrderId()),
					channelPayCall.getMsg(), "验证errorMessage");
			Logger.verifyEquals("ErrOrderNotExists", channelPayCall.getCode(),
					"验证errorCode");

		} catch (Exception e) {
			Logger.fail(e);
		}
	}
}
